#include "TIndice.h"
#include "TTokenizer.h"


/**funciones axiliares**/

/**estos son los 2 comparadores para el abo, dps veo si los meto en algun lugar mas prolijo**/
int comparadorTweet(void* elem1, void* elem2){
    TElemArbolTweet* campo1 = NULL;
    TElemArbolTweet* campo2 = NULL;
    int resultadoComparacion;
    campo1 = (TElemArbolTweet*)elem1;
    campo2 = (TElemArbolTweet*)elem2;
    resultadoComparacion = strcmp(campo1->Clave.Nombre, campo2->Clave.Nombre);
    if (resultadoComparacion<0){
        return MENOR;
    }else if (resultadoComparacion>0){
        return MAYOR;
    }else{
        resultadoComparacion = strcmp(campo1->Clave.Fecha, campo2->Clave.Fecha);
        if (resultadoComparacion<0){
            return MENOR;
        }else if (resultadoComparacion>0){
            return MAYOR;
        }else{
            return IGUAL;
        }
    }
}


int comparadorTerminos(void* elem1, void* elem2){
    TElemArbolTerminos* campo1 = NULL;
    TElemArbolTerminos* campo2 = NULL;
    int resultadoComparacion;
    campo1 = (TElemArbolTerminos*)elem1;
    campo2 = (TElemArbolTerminos*)elem2;
    resultadoComparacion = strcmp(campo1->termino, campo2->termino);
    if (resultadoComparacion<0){
        return MENOR;
    }else if (resultadoComparacion>0){
        return MAYOR;
    }else{
        return IGUAL;
    }

}

/**comparador de clave doble**/
int comparadorStringDoble(void* elem1, void* elem2){
    TClaveTweet* campo1 = NULL;
    TClaveTweet* campo2 = NULL;
    int resultadoComparacion;
    campo1 = (TClaveTweet*)elem1;
    campo2 = (TClaveTweet*)elem2;
    resultadoComparacion = strcmp(campo1->Nombre, campo2->Nombre);
    if (resultadoComparacion<0){
        return MENOR;
    }else if (resultadoComparacion>0){
        return MAYOR;
    }else{
        resultadoComparacion = strcmp(campo1->Fecha, campo2->Fecha);
        if (resultadoComparacion<0){
            return MENOR;
        }else if (resultadoComparacion>0){
            return MAYOR;
        }else{
            return IGUAL;
        }
    }
}


/**otra**/

int BuscarPalabra(TABO* Arbol,char* termino,int mov){
    TElemArbolTerminos ElemAux;
    int err=0;
    int Resultado;
    /*hago todo suponiendo que esta ordenado el arbol*/
    /*muevo el corriente*/
    err=ABO_MoverCte(Arbol,mov);
    if(err==0){ /*o sea que termino de recorrerlo y no estaba*//*devuelve 0 cuando no movio*/
        return 1;
    }
    else{
        ABO_Obtener(Arbol,&ElemAux);
        if(strcmp(ElemAux.termino,termino)==0){
            /*lo encontro, y el corriente quedo apuntando ahi*/
            return 0;
        }
        else if(strcmp(ElemAux.termino,termino)<0){
            /*el que busco es mas grande, muevo a derecha*/
            Resultado=BuscarPalabra(Arbol,termino,DER);
        }
        else{
            /*el que busco es mas chicomuevo a la izquierda*/
            Resultado=BuscarPalabra(Arbol,termino,IZQ);
        }
    }
    return Resultado;
}

/**otra**/
int BuscarTweet(TABO* Arbol,TClaveTweet* ClaveBuscada,int mov){
    TElemArbolTweet ElemAux;
    int err=0;
    int Resultado;
    err=ABO_MoverCte(Arbol,mov);
    if(err==0){ /*o sea que termino de recorrerlo y no estaba*/
        return 1;
    }
    else{
        ABO_Obtener(Arbol,&ElemAux);
        if(comparadorStringDoble(&ElemAux.Clave,ClaveBuscada)==0){
            /*lo encontro, y el corriente quedo apuntando ahi*/
            Resultado=0;
        }
        else if(comparadorStringDoble(&ElemAux.Clave,ClaveBuscada)<0){
            /*el que busco es mas grande, muevo a derecha*/
            Resultado=BuscarTweet(Arbol,ClaveBuscada,DER);
        }
        else{
            /*el que busco es mas chicomuevo a la izquierda*/
            Resultado=BuscarTweet(Arbol,ClaveBuscada,IZQ);
        }
    }

    return Resultado;
}

/**otra**/
int InsertarTerminos(TIndice* ti,TListaSimpleOrdenada* Lista ,TElemArbolTerminos* ElemTerm,TClaveTweet* Doc){
    char Palabra[MAX_DATO];
    int err=0;
    if(!lso_Vacia(*Lista)){
        /*muevo al primero*/
        lso_MoverCorriente(Lista,LS_PRIMERO);/*devuelve 0 si todo ok*/
        /*voy sacando las palabras de a una hasta que se termine la lista*/
        while(err==0){
            lso_ElemCorriente(*Lista,Palabra);
            /*copio el termino*/
            strcpy(ElemTerm->termino,Palabra);
            /*me fijo si el termino ya estaba*/
            /*me armo la funcion auxiliar buscar palabra, 0 si encuentra, 1 si no. me deja el corriente donde esta el termino buscado*/
            if(BuscarPalabra(&ti->ArbolTerminos,ElemTerm->termino, RAIZ)!=0){ /*o sea que no estaba*/ /*si estaba vacio va a devolver 1 igual*/
                /*tendria que crear la lista, y no liberarla porque es la que voy a insertar*/
                lso_Crear(&ElemTerm->ListaDocs,sizeof(TClaveTweet),&comparadorStringDoble);
                /*inserto en la lista*//*no me parece q sea asi nomas, no me gusta nada*/
                lso_Insertar(&ElemTerm->ListaDocs,Doc);
                /*inserto en el arbol*//*si ya estaba modifico no inserto*/
                ABO_Insertar(&ti->ArbolTerminos,ElemTerm);
            }
            else{
                /*paso lo de la lista vieja a esta*/
                /*si lo encontro, lo dejo en el corriente, entonces obtengo la lista*/
                ABO_Obtener(&ti->ArbolTerminos,ElemTerm);
                /*inserto en la lista*//*no me parece q sea asi nomas, no me gusta nada*/
                lso_Insertar(&ElemTerm->ListaDocs,Doc);
                /*inserto en el arbol*//*si ya estaba modifico no inserto*/
                ABO_Actualizar(&ti->ArbolTerminos,ElemTerm);
            }
            err=lso_MoverCorriente(Lista,LS_SIGUIENTE);
        }
    }
    return 0;
}


/**otra**/

int BorrarAmbosLados(TABO* Arbol,TClaveTweet* ClaveBuscada,int mov){
    int err=0;
    /**TClaveTweet ClaveAux;**/
    TElemArbolTweet ElemAux;
    /*comparo solo por el nombre*/
    err=ABO_MoverCte(Arbol,mov);
    if(err!=0){
        ABO_Obtener(Arbol,&ElemAux);
        if(strcmp(ClaveBuscada->Nombre,ElemAux.Clave.Nombre)==0){
            /*lo tengo que borrar*/
            ElemAux.Activo=false;
            ABO_Actualizar(Arbol,&ElemAux);
            /*y despues borrar a ambos lados*/
            BorrarAmbosLados(Arbol,ClaveBuscada,DER);
            BorrarAmbosLados(Arbol,ClaveBuscada,IZQ);
        }
        else if(strcmp(ClaveBuscada->Nombre,ElemAux.Clave.Nombre)>0){
            /*llamo al borrar solo a derecha*/
            BorrarAmbosLados(Arbol,ClaveBuscada,DER);
        }
        else{
            /*llamo al borrar solo a izquierda*/
            BorrarAmbosLados(Arbol,ClaveBuscada,IZQ);
        }
        /*lo vuelvo a subir*//*ver si hay que subir una o dos veces*/
        err=ABO_MoverCte(Arbol,PAD);
    }
    return 0;
}

/**otra**/
int Procesar(TIndice* ti,TDiccionario* Tweet){
    /*pasa el texto de los tweets que voy obteniendo de nuevo por el tokenizer(solo si el tweet esta activo)*/
    /*y de ahi voy agregando otra vez al arbol de terminos*/
    char texto[MAX_DATO];
    char nombre[MAX_DATO];
    char fecha[MAX_DATO];
    /*Lista donde se van a devolver los terminos pasados por el tokenizer*/
    TListaSimpleOrdenada ListaTerminos;
    TElemArbolTerminos ElemAuxTerm;
    TClaveTweet DocAux;
    /*obtengo el text, pasando clave="text" en el diccionario obtener*/
    TDiccionario_obtener(Tweet,"text",texto);
    /*lo mismo hago para nombre y fecha*/
    TDiccionario_obtener(Tweet,"user|screen_name",nombre);
    TDiccionario_obtener(Tweet,"created_at",fecha);
    /*chigo armando*/
    strcpy(DocAux.Nombre,nombre);/*el docaux lo uso mas adelante*/
    strcpy(DocAux.Fecha,fecha);
    /*creo la lista*/
    lso_Crear(&ListaTerminos,256*sizeof(char),&comparadorString);
    /*mando el text al tokenizer*/
    TTokenizer_analizar(&ti->Tokenizer,texto,&ListaTerminos);
    /*agrego los terminos al arbol de terminos*/
    InsertarTerminos(ti,&ListaTerminos,&ElemAuxTerm,&DocAux);
    /*destruyo la lista una vez que quedo vacia(o sea que ya pase todos los terminos)*/
    lso_Vaciar(&ListaTerminos);

    return 0;
}

/**otra**/
int RecorrerInOrden(TIndice* ti){
    /*izq, procesar, der*/
    int err;
    TElemArbolTweet ElemAux;
    /*muevo a izquierda*/
    err=ABO_MoverCte(&ti->ArbolTweets,IZQ);
    if(err!=0){
        RecorrerInOrden(ti);
        err=ABO_MoverCte(&ti->ArbolTweets,PAD);
    }
    /*proceso*/
    ABO_Obtener(&ti->ArbolTweets,&ElemAux);
    if(ElemAux.Activo==true){
        Procesar(ti,&ElemAux.Documento);
    }
    /*muevo a derecha*/
    err=ABO_MoverCte(&ti->ArbolTweets,DER);
    if(err!=0){
        RecorrerInOrden(ti);
        err=ABO_MoverCte(&ti->ArbolTweets,PAD);
    }
    return 0;
}

/*los arboles se van armando a medida que van agregando tweets. el tema de la optimizacion hay que prestarle atencion, ver bien como seria*/

int TIndice_crear(TIndice* ti, TTokenizer* ta){
    ABO_Crear(&ti->ArbolTweets,&comparadorTweet,sizeof(TElemArbolTweet));
    ABO_Crear(&ti->ArbolTerminos,&comparadorTerminos,sizeof(TElemArbolTerminos));
    /*setteo el tokenizer*/
    memcpy(&ti->Tokenizer,ta,sizeof(TTokenizer));

    return 0;
}

int TIndice_destruir(TIndice* ti){
    /*vacio los arboles*/
    ABO_Destruir(&ti->ArbolTweets);
    ABO_Destruir(&ti->ArbolTerminos);

    return 0;
}


int TIndice_agregar(TIndice* ti, TDiccionario* Tweet){
    char texto[MAX_DATO];
    char nombre[MAX_DATO];
    char fecha[MAX_DATO];
    /*Lista donde se van a devolver los terminos pasados por el tokenizer*/
    TListaSimpleOrdenada ListaTerminos;
    /*Elemento para aca armar lo q lego se va a insertar en el arbol de tweets*//*es legal hacerlo asi???*/
    TElemArbolTweet ElemAuxTwt;
    TElemArbolTerminos ElemAuxTerm;
    TClaveTweet DocAux;
    /*obtengo el text, pasando clave="text" en el diccionario obtener*/
    TDiccionario_obtener(Tweet,"text",texto);
    /*lo mismo hago para nombre y fecha*/
    TDiccionario_obtener(Tweet,"user|screen_name",nombre);
    TDiccionario_obtener(Tweet,"created_at",fecha);
    /*armo la estructura del elem del ab_tweets*/
    /**REVISAR**/
    ElemAuxTwt.Activo=true;
    ElemAuxTwt.Documento=*Tweet;
    /*chigo armando*/
    strcpy(DocAux.Nombre,nombre);/*el docaux lo uso mas adelante*/
    strcpy(DocAux.Fecha,fecha);
    ElemAuxTwt.Clave=DocAux;
    /*ahora si inserto en el arbol*/
    ABO_Insertar(&ti->ArbolTweets,&ElemAuxTwt);
    /*creo la lista*/
    lso_Crear(&ListaTerminos,256*sizeof(char),&comparadorString);
    /*mando el text al tokenizer*/
    TTokenizer_analizar(&ti->Tokenizer,texto,&ListaTerminos);
    /*agrego los terminos al arbol de terminos*/
    InsertarTerminos(ti,&ListaTerminos,&ElemAuxTerm,&DocAux);
    /*destruyo la lista una vez que quedo vacia(o sea que ya pase todos los terminos)*/
    lso_Vaciar(&ListaTerminos);
    /*devuelvo OK*/
    return 0;
}


int TIndice_listarDocs(TIndice* ti, char* termino, TListaSimpleOrdenada * docs){
    /*tengo que devolver una lista de punteros a los diccionarios(tweets) que tienen el termino*/
    /*supongo que este lo va a usar el buscador, aunque en realidad no estoy todavia seguro de lo que hace para quien*/
    int err=0;
    TClaveTweet ClaveAux;
    TElemArbolTerminos ElemAuxTerm;
    TElemArbolTweet ElemAuxTweet;
    /**TDiccionario* TweetAux =(TDiccionario*) malloc(sizeof(TDiccionario));**/ /**= (TDiccionario*) malloc(sizeof(TDiccionario));**//**tengo que hacer un malloc para esto?**/
    lso_Crear(&ElemAuxTerm.ListaDocs,sizeof(TClaveTweet),&comparadorStringDoble);
    /*tendria que recorrer el arbol de terminos buscando el termino que me pasaron*/
    if(BuscarPalabra(&ti->ArbolTerminos,termino, RAIZ)==0){
    /*si lo encuentro, devuelvo la lista qe tiene en el struct*/
        ABO_Obtener(&ti->ArbolTerminos,&ElemAuxTerm);
        if(!lso_Vacia(ElemAuxTerm.ListaDocs)){
            lso_MoverCorriente(&ElemAuxTerm.ListaDocs,LS_PRIMERO);/*al primero*/
            while(err==0){
                /*voy recorriendo y pasando los punteros a la otra lista*/
                lso_ElemCorriente(ElemAuxTerm.ListaDocs,&ClaveAux);
                /*busco el tweet que tiene esa clave*/
                if(BuscarTweet(&ti->ArbolTweets,&ClaveAux,RAIZ)==0){
                    /*obtengo el corriente de ese arbol(que seria el tweet buscado)*/
                    ABO_Obtener(&ti->ArbolTweets,&ElemAuxTweet);
                    if(ElemAuxTweet.Activo==true){
                        /**TweetAux=&ElemAuxTweet.Documento;**/
                        TDiccionario* TweetAux =(TDiccionario*) malloc(sizeof(TDiccionario));
                        memcpy(TweetAux,&ElemAuxTweet.Documento,sizeof(TDiccionario));/**estoy copiando el puntero???**/
                        /**aca voy a insertar solo los que esten activos**/
                        lso_Insertar(docs,&TweetAux);/*le paso un puntero a un puntero a diccionario*/
                    }
                }
                /*vuelvo a mover*/
                err=lso_MoverCorriente(&ElemAuxTerm.ListaDocs,LS_SIGUIENTE);
            }
        }
    }
    /**free(TweetAux);**//**esta linea va solo si va el malloc y solo si no se inserto en la lista**/
    /*sino devuelvo vacio(ver a que me refiero con que devuelvo vacio), vuelve como esta??*/
    /*destruyo la lista auxiliar*/
    /*lso_Vaciar(&ElemAuxTerm.ListaDocs);*/

    return 0;
}

int TIndice_eliminarTweet(TIndice* ti, char* usuario, char* fecha){
    /*recorro el arbol de tweets, en busca del usuario y fechas pasados*/
    TClaveTweet ClaveBuscada;
    TClaveTweet ClaveAux;
    TElemArbolTweet ElemAux;
    int err=0;
    int comp=1;
    strcpy(ClaveBuscada.Nombre,usuario);
    strcpy(ClaveBuscada.Fecha,fecha);
    /*hago todo suponiendo que esta ordenado el arbol*/
    /*muevo el corriente*/
    err=ABO_MoverCte(&ti->ArbolTweets,RAIZ);/*1 si movio, 0 si no*/
    while((err!=0)&&(comp!=0)){
        ABO_Obtener(&ti->ArbolTweets,&ElemAux);
        ClaveAux=ElemAux.Clave;
        comp=comparadorStringDoble(&ClaveBuscada,&ClaveAux);
        if(comp>0){
            err=ABO_MoverCte(&ti->ArbolTweets,DER);
        }
        else if(comp<0){
            err=ABO_MoverCte(&ti->ArbolTweets,IZQ);
        }
    }
    if(err!=0){ /* => comp==0, lo encontro*/
        /*lo elimino(logico) y lo modifico*/
        ElemAux.Activo=false;
        ABO_Actualizar(&ti->ArbolTweets,&ElemAux);
    }

    return 0;
}

int TIndice_eliminarUsuario(TIndice* ti, char* usuario){
    /*recorro el arbol, pero no paro cando encuentro el tweet, pq puede haber mas de uno del mismo usuario con distintas fechas*/
    TClaveTweet ClaveBuscada;
    TClaveTweet ClaveAux;
    TElemArbolTweet ElemAux;
    int err=0;
    int comp;
    strcpy(ClaveBuscada.Nombre,usuario);

    err=ABO_MoverCte(&ti->ArbolTweets,RAIZ);
    if(err!=0){
        ABO_Obtener(&ti->ArbolTweets,&ElemAux);
        ClaveAux=ElemAux.Clave;
        comp=strcmp(ClaveBuscada.Nombre,ClaveAux.Nombre);
        if(comp==0){
            /*lo elimino(logico) y lo modifico*/
            ElemAux.Activo=false;
            ABO_Actualizar(&ti->ArbolTweets,&ElemAux);
            /**tengo que mover a izquierda y derecha, revisar bien la cond de corte, y demases**/
            /*hago uno a derecha y otro a izquierda*/
            BorrarAmbosLados(&ti->ArbolTweets,&ClaveBuscada,DER);
            BorrarAmbosLados(&ti->ArbolTweets,&ClaveBuscada,IZQ);
        }
        else if(comp>0){
            BorrarAmbosLados(&ti->ArbolTweets,&ClaveBuscada,DER);
        }
        else{
            BorrarAmbosLados(&ti->ArbolTweets,&ClaveBuscada,IZQ);
        }
    }
    return 0;
}

int TIndice_optimizar(TIndice* ti){
    int err;
    /*elimino el arbol de terminos(liberar todos los recursos asociados)*/
    ABO_Destruir(&ti->ArbolTerminos);
    /*y creo el nuevo*/
    ABO_Crear(&ti->ArbolTerminos,&comparadorTerminos,sizeof(TElemArbolTerminos));
    /*recorro el arbol de tweets y armo uno nuevo de terminos con los tweets quue estan activos nada mas*/
    /*uso inOrden que me parece el mas adecuado, para ir recorriendo el de tweets*//*izquierda, proceso, derecha*/
    /*empiezo poniendolo en la raiz*/
    err=ABO_MoverCte(&ti->ArbolTweets,RAIZ);
    if(err!=0){
        RecorrerInOrden(ti);/*le paso el indice entero, pq mas alla de recorer el abtweets procesa pasando al de terminos nuevo*/
    }
    /*cuando termine de recorrer el arbol de tweets y procese todo ya ta*/
    return 0;
}
